package com.zm.demo.core.concurrent;

import org.junit.Test;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

import static java.lang.System.out;

/**
 * @author zoum
 * @create 2019/7/2 11:40
 */
public class DelayQueueTest {

    @Test
    public void test() throws InterruptedException{
        DelayQueue<DelayedCase> delayQueue = new DelayQueue<DelayedCase>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.sss");
        out.println("start " + sdf.format(new Date()));
        delayQueue.add(new DelayedCase(10000L));
        delayQueue.add(new DelayedCase(11000L));
        delayQueue.add(new DelayedCase(2000L));
        delayQueue.add(new DelayedCase(5000L));
        delayQueue.add(new DelayedCase(3500L));
        delayQueue.add(new DelayedCase(4000L));

        int i=0;
        while (delayQueue.size() > 0 && delayQueue.take() != null){
//            Thread.sleep(1000L);
            out.println("expired " + sdf.format(new Date()));
        }


    }


    class DelayedCase implements Delayed{

        private long deadLineTime;
        private long delay;

        public DelayedCase(long delay){
            this.delay = delay;
            deadLineTime = System.currentTimeMillis() + delay;
        }

        /**
         * Returns the remaining delay associated with this object, in the
         * given time unit.
         *
         * @param unit the time unit
         * @return the remaining delay; zero or negative values indicate
         * that the delay has already elapsed
         */
        @Override
        public long getDelay(TimeUnit unit) {
            return unit.convert(Math.max(0L, deadLineTime - System.currentTimeMillis()), TimeUnit.MICROSECONDS);
//            return Math.max(0L, deadLineTime - System.currentTimeMillis());
        }

        /**
         * Compares this object with the specified object for order.  Returns a
         * negative integer, zero, or a positive integer as this object is less
         * than, equal to, or greater than the specified object.
         * <p>
         * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
         * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
         * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
         * <tt>y.compareTo(x)</tt> throws an exception.)
         * <p>
         * <p>The implementor must also ensure that the relation is transitive:
         * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
         * <tt>x.compareTo(z)&gt;0</tt>.
         * <p>
         * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
         * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
         * all <tt>z</tt>.
         * <p>
         * <p>It is strongly recommended, but <i>not</i> strictly required that
         * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
         * class that implements the <tt>Comparable</tt> interface and violates
         * this condition should clearly indicate this fact.  The recommended
         * language is "Note: this class has a natural ordering that is
         * inconsistent with equals."
         * <p>
         * <p>In the foregoing description, the notation
         * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
         * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
         * <tt>0</tt>, or <tt>1</tt> according to whether the value of
         * <i>expression</i> is negative, zero or positive.
         *
         * @param o the object to be compared.
         * @return a negative integer, zero, or a positive integer as this object
         * is less than, equal to, or greater than the specified object.
         * @throws NullPointerException if the specified object is null
         * @throws ClassCastException   if the specified object's type prevents it
         *                              from being compared to this object.
         */
        @Override
        public int compareTo(Delayed o) {
            DelayedCase other = (DelayedCase)o;
            return delay - other.delay > 0 ? 1 : delay - delay - other.delay < 0 ? -1 : 0;
        }
    }
}
